package com.chen.judge;

import cn.hutool.json.JSONUtil;
import com.chen.common.constant.MessageConstant;
import com.chen.judge.codesandbox.CodeSandbox;
import com.chen.judge.codesandbox.CodeSandboxFactory;
import com.chen.judge.codesandbox.CodeSandboxProxy;
import com.chen.judge.codesandbox.model.ExecuteCodeRequest;
import com.chen.judge.codesandbox.model.ExecuteCodeResponse;
import com.chen.judge.codesandbox.model.JudgeResult;
import com.chen.judge.codesandbox.model.JudgeContext;
import com.chen.mapper.JudgeCaseMapper;
import com.chen.mapper.ProblemMapper;
import com.chen.mapper.SamplesMapper;
import com.chen.popj.entity.JudgeCase;
import com.chen.popj.entity.Problem;
import com.chen.popj.entity.ProblemSubmit;
import com.chen.service.ProblemService;
import com.chen.service.ProblemSubmitService;
import com.chen.websocket.WebSocketServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;


@Service
public class JudgeServiceImpl implements JudgeService {

    @Autowired
    private ProblemService problemService;

    @Autowired
    private ProblemSubmitService problemSubmitService;

    @Autowired
    private JudgeManager judgeManager;

    @Autowired
    JudgeCaseMapper judgeCaseMapper;

    @Autowired
    WebSocketServer webSocketServer;

    @Autowired
    ProblemMapper problemMapper;
    @Value("${codesandbox.type:example}")
    private String type;


    @Override
    public ProblemSubmit doJudge(Integer problemSubmitId) {
        // 1）传入题目的提交 id，获取到对应的题目、提交信息（包含代码、编程语言等）
        ProblemSubmit problemSubmit = problemSubmitService.getById(problemSubmitId);
        if (problemSubmit == null) {
            throw new RuntimeException(MessageConstant.SUBMIT_MESSAGE_NOT_FOUND);
        }
        Integer problemId = problemSubmit.getProblemId();
        Problem problem = problemService.getById(problemId);
        if (problem == null) {
            throw new RuntimeException(MessageConstant.PROBLEM_NOT_FAILED);
        }
        // 2）如果题目提交状态不为等待中，就不用重复执行了

        // 3）更改判题（题目提交）的状态为 “判题中”，防止重复执行

        // 4）创建沙箱
        CodeSandbox codeSandbox = new CodeSandboxProxy(CodeSandboxFactory.newInstance(type));
        String language = problemSubmit.getLanguage();
        String code = problemSubmit.getCode();
        // 获取判题测试用例
//        String judgeCaseStr = problem.getJudgeCase();
//        List<JudgeCase> judgeCaseList = JSONUtil.toList(judgeCaseStr, JudgeCase.class);
        List<JudgeCase> judgeCaseList = judgeCaseMapper.getJudgeCase(problemId);

//        List<String> inputList = samplesMapper.getInput(problemId);
        List<String> inputList = judgeCaseMapper.getInput(problemId);
        ExecuteCodeRequest executeCodeRequest = ExecuteCodeRequest.builder()
                .code(code)
                .language(language)
                .inputList(inputList)
                .build();
        // 5） 调用沙箱，获取到执行结果
        ExecuteCodeResponse executeCodeResponse = codeSandbox.executeCode(executeCodeRequest);
        if (executeCodeResponse.getStatus() == 1) {
            JudgeResult judgeResult = new JudgeResult();
            judgeResult.setMessage("编译错误");
            updateById(problemSubmit.getId(), judgeResult);
            System.out.println(executeCodeResponse.getMessage());
            throw new RuntimeException("编译错误");
        }
//        List<String> outputList = executeCodeResponse.getOutputList();
        List<String> outputList = new ArrayList<>();
        judgeCaseList.forEach((judgeCase) -> {
            outputList.add(judgeCase.getOutput());
        });
        System.out.println("outputList:" + outputList);
        // 6）根据沙箱的执行结果，设置题目的判题状态和信息
        JudgeContext judgeContext = new JudgeContext();
        judgeContext.setJudgeInfoList(executeCodeResponse.getJudgeInfoList());
        judgeContext.setInputList(inputList);
        judgeContext.setOutputList(outputList);
        judgeContext.setJudgeCaseList(judgeCaseList);
        judgeContext.setProblem(problem);
        judgeContext.setProblemSubmit(problemSubmit);
        // 使用测试点进行判题
        JudgeResult judgeResult = judgeManager.doJudge(judgeContext);
        // 7）修改数据库中的判题结果
//        String jsonStr = JSONUtil.toJsonStr(judgeResult);
        updateById(problemSubmit.getId(), judgeResult);
//        ProblemSubmit submit = new ProblemSubmit();
//        submit.setId(problemSubmit.getId());
//        submit.setJudgeInfo(jsonStr);
//        problemSubmitService.updateById(submit);
        ProblemSubmit problemSubmitResult = problemSubmitService.getById(problemId);
        if ("Accepted".equals(judgeResult.getMessage())) {
            //该题通过次数+1
            Problem build = Problem.builder()
                    .id(problemId)
                    .acceptedNumber(1)
                    .build();
            problemMapper.updateById(build);
        }
        return problemSubmitResult;
    }

    private void updateById(Integer problemSubmitId, JudgeResult judgeResult) {
        String jsonStr = JSONUtil.toJsonStr(judgeResult);
        ProblemSubmit submit = new ProblemSubmit();
        submit.setId(problemSubmitId);
        submit.setJudgeInfo(jsonStr);
        // 通过WebSocket把判题结果返回给前端
        webSocketServer.sendClient(problemSubmitId, judgeResult);
        problemSubmitService.updateById(submit);
    }
}
